from io import BytesIO
import base64
from PIL import Image
from odoo import models, fields, api, _

from odoo.exceptions import UserError, ValidationError


class report_product_production_view(models.AbstractModel):
    _name = 'report.pcbmanufact.report_product_production_view'

    @api.model
    def _get_report_values(self, docids, data=None):
        self = self.sudo()
        report = self.env['ir.actions.report']._get_report_from_name(
            'pcbmanufact.report_product_production_instruction')
        docs = self.env['product.template'].with_context(lang='zh_CN').browse(docids)
        # 初始化列表，分别存储不同字段的多个数据
        uom_data_list = []
        spec_values_list = []
        customer_details_list = []
        drill_lists = []
        back_drill_lists = []
        drill_image_list = []
        spec_values_eng_list = []
        image_info_list = []
        hf_pcb_list = []
        try:
            for doc in docs:
                production_param_values = {}
                production_spec_values = {}
                uom_data = self.get_unit_number(doc)
                customer_details, pn_on_pcb = self.get_customer_details(doc)
                for param in doc.param_line_ids:
                    param_dict = {
                        'attribute_name': param.attribute_id.name,
                        'value_name': param.value_id.name if param.value_id else None,
                        'eng_name': param.z_eng_name if param.value_id and param.z_eng_name else None,
                    }
                    production_param_values[param.attribute_id.name] = param_dict
                for spec in doc.spec_line_ids:
                    spec_dict = {
                        'attribute_name': spec.attribute_id.name,
                        'value_name': spec.value_id.name if spec.value_id else None,
                        'eng_name': spec.z_eng_name if spec.value_id and spec.z_eng_name else None,
                    }
                    production_spec_values[spec.attribute_id.name] = spec_dict
                combined_values = production_spec_values.copy()  # 先复制 spec_values 避免修改原始数据
                combined_values.update(production_param_values)  # 将 param_values 合并进 spec_values
                verified_data, verified_data_eng = self.get_verified_data(combined_values)
                drill_image, drill_list, back_drill_list = self.get_drill_data(doc)
                hf_pcb = str(doc.default_code)[3] == 'H'
                img_info = {}
                if hasattr(doc, 'cutting_drawing_image') and doc.cutting_drawing_image:
                    img_info['cutting_drawing'] = self.get_image_info(doc.cutting_drawing_image)
                if hasattr(doc, 'stack_up_image') and doc.stack_up_image:
                    img_info['stack_up'] = self.get_image_info(doc.stack_up_image)
                image_info_list.append(img_info)
                # 塞进去列表中
                uom_data_list.append(uom_data)
                hf_pcb_list.append(hf_pcb)
                spec_values_list.append(verified_data)
                spec_values_eng_list.append(verified_data_eng)
                customer_details_list.append(customer_details)
                drill_image_list.append(drill_image)
                drill_lists.append(drill_list)
                back_drill_lists.append(back_drill_list)
        except Exception as e:
            raise e
        return {
            'doc_model': 'product.template',
            'docs': docs,
            'data': data,
            'uom_data_list': uom_data_list,
            'spec_values_list': spec_values_list,
            'spec_values_eng_list': spec_values_eng_list,
            'customer_details_list': customer_details_list,
            'drill_lists': drill_lists,
            'back_drill_lists': back_drill_lists,
            'drill_image_list': drill_image_list,
            'image_info_list': image_info_list,
            'hf_pcb_list': hf_pcb_list,
        }

    def get_image_info(self, image_field):
        """解析图片，返回图片的原始尺寸、格式以及缩放后的尺寸，保证缩放后高度不超过1400px"""
        try:
            image_data = base64.b64decode(image_field)
            image = Image.open(BytesIO(image_data))
            orig_width = image.width
            orig_height = image.height
            # 按固定宽度1200px计算缩放比例
            scale_by_width = 1100 / orig_width if orig_width else 1
            computed_height = orig_height * scale_by_width
            # 如果计算后的高度超过1400，则以高度为准重新计算缩放比例
            if computed_height > 1400:
                scale = 1400 / orig_height
            else:
                scale = scale_by_width
            scaled_width = int(orig_width * scale)
            scaled_height = int(orig_height * scale)
            return {
                'width': orig_width,
                'height': orig_height,
                'format': image.format,
                'scaled_width': scaled_width,
                'scaled_height': scaled_height,
            }
        except Exception as e:
            return {}

    # 数据整理
    def get_verified_data(self, combined_values):
        dic = {
            '层数': None,
            '内层基铜厚': None,
            '内层完成铜厚': None,
            '外层基铜厚': None,
            '外层完成铜厚': None,
            '外型公差': None,
            '成品板厚': None,
            '板厚公差': None,
            '板厚测点': None,
            '板子特性': None,
            '压合程式': None,
            '制作人': None,
            '表面处理': None,
            '通孔厚径比': None,
            '激光孔厚径比': None,
            '叉板率': None,
            'Tg': None,
            'X-Out(叉板)': None,
            'D2C机械孔-内层铜': None,
            'DHS机械孔': None,
            '长边工艺边': None,
            '短边工艺边': None,
            'D2D不同网络孔边-孔边': None,
            'LDS激光孔': None,
            '产品类别': None,
            '附注': None,
            '注解': None,
            '难度等级': None,
            '线路工艺': None,
            '测量位置Top': None,
            '测量位置Bot': None,
            '板上型号': None,
            '产品特征': None,
            '产品应用': None
        }
        dic_eng = {
            '表面处理': None,
            '板厚测点': None,
            '线路工艺': None,
            '测量位置Bot': None,
            '测量位置Top': None,
        }
        for key, value in combined_values.items():
            if key in dic:  # 如果字典dic中存在这个key
                dic[key] = value['value_name']  # 将dic中的value更新为value_name的值
            if key in dic_eng:
                dic_eng[key] = value['eng_name']
            # else: #追加
            #     dic[key] = value['value_name']
        return dic, dic_eng

    # 钻孔图
    def get_drill_data(self, docs):
        """
        從鑽孔文件中獲取鑽孔圖片和鑽孔列表。
        :param docs: 鑽孔文件（可能是 recordset）。
        :return: 包含 'images' (圖片列表) 和 'drill_list' (鑽孔操作列表) 的字典。
        """
        images = []
        drill_list = []
        back_drill_list = []
        for doc in docs:
            # 檢查是否存在 BOM，並確保它是非空的 recordset
            if not doc.bom_ids or not doc.bom_ids[0]:
                return None, None
            for bom in doc.bom_ids:  # 直接遍歷 bom_ids
                for operation in bom.operation_ids:
                    if operation.drill_image:
                        images.append(operation.drill_image)
                    if operation.drill_operation_ids:
                        drill_list.append(operation.drill_operation_ids)
                    if operation.back_drill_operation_ids:
                        back_drill_list.append(operation)

        return images, drill_list, back_drill_list

    def get_customer_details(self, docs):
        """
        Recursively find the top-level customer item code details.
        This function traverses through the hierarchy of BOM lines to find the top-level customer item code.
        """

        def find_top_level_customer_code(record):
            # 如果当前记录有 customer_item_code_ids，直接返回
            codes = record.with_context(active_test=False).customer_item_code_ids
            if codes:
                # 按 id 降序取最新一筆
                latest = codes.sorted('id', reverse=True)[:1]
                pn_on_pcb = latest.customer_item_desc.split()[0] if latest.customer_item_desc else ''
                return latest, pn_on_pcb
            # 如果当前记录没有 customer_item_code_ids，但有 bom_line_ids，递归查找
            if record.bom_line_ids:
                for bom_line in record.bom_line_ids:
                    # 递归调用 find_top_level_customer_code
                    result = find_top_level_customer_code(bom_line.bom_id.product_tmpl_id)
                    if result:
                        return result

            # 如果没有找到任何记录，返回 None, None
            return None, None

        # 调用递归函数
        return find_top_level_customer_code(docs)

    def get_unit_number(self, docs):
        def format_number(value):
            """
            格式化数字，去除多余的零和小数点。
            """
            if value.is_integer():  # 检查是否为整数
                return int(value)  # 转换为整数
            else:
                return value  # 保留小数部分

        def is_within_range(value, lower, upper):
            """判断值是否在区间内"""
            return lower <= value <= upper

        def get_ordered_dimensions(pnl_width, pnl_length):  # 0224not use   现在在创建之初就确定了左右位置
            # 定义区间
            ranges = [
                (580, 625),
                (390, 420),
                (290, 315),
                (230, 250)
            ]

            # 判断 pnl_width 和 pnl_length 是否在区间内
            width_in_range = [is_within_range(pnl_width, lower, upper) for lower, upper in ranges]
            length_in_range = [is_within_range(pnl_length, lower, upper) for lower, upper in ranges]

            # 如果两者都在区间内，按照大小排序
            if any(width_in_range) and any(length_in_range):
                if pnl_width > pnl_length:
                    return f"{format_number(pnl_length)} * {format_number(pnl_width)}"
                else:
                    return f"{format_number(pnl_width)} * {format_number(pnl_length)}"

            # 如果只有一个值符合区间条件
            if any(width_in_range) and not any(length_in_range):
                return f"{format_number(pnl_length)} * {format_number(pnl_width)}"
            elif any(length_in_range) and not any(width_in_range):
                return f"{format_number(pnl_width)} * {format_number(pnl_length)}"

            # 如果两个值都不在区间中，按大小排序
            if pnl_width > pnl_length:
                return f"{format_number(pnl_length)} * {format_number(pnl_width)}"
            else:
                return f"{format_number(pnl_width)} * {format_number(pnl_length)}"

        uom_panel_width = self.env.ref('pcbmanufact.uom_panel_width')
        uom_panel_length = self.env.ref('pcbmanufact.uom_panel_length')
        uom_set_width = self.env.ref('pcbmanufact.uom_set_width')
        uom_set_length = self.env.ref('pcbmanufact.uom_set_length')
        uom_pcs_width = self.env.ref('pcbmanufact.uom_pcs_width')
        uom_pcs_length = self.env.ref('pcbmanufact.uom_pcs_length')
        uom_set = self.env.ref('pcbmanufact.uom_set')
        uom_pcs = self.env.ref('pcbmanufact.uom_part')  # pcs
        uom_panel = self.env.ref('pcbmanufact.uom_panel')
        uom_ids = docs.uom_value_ids.mapped('uom_id')

        if uom_panel_width in uom_ids and uom_panel_length in uom_ids and uom_set_width in uom_ids and uom_set_length in uom_ids:
            pnl_width = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_panel_width.id).uom_value
            pnl_length = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_panel_length.id).uom_value
            set_width = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_set_width.id).uom_value
            set_length = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_set_length.id).uom_value
            pcs_width = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_pcs_width.id).uom_value
            pcs_length = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_pcs_length.id).uom_value
            panel = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_panel.id).uom_value
            pcs = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_pcs.id).uom_value
            set = docs.uom_value_ids.filtered(lambda x: x.uom_id.id == uom_set.id).uom_value
            # sheet_length = docs.uom_value_ids.filtered(lambda x: x.uom_id.name == "SHETL").uom_value
            # sheet_width = docs.uom_value_ids.filtered(lambda x: x.uom_id.name == "SHETW").uom_value
            pcs_in_sheet = docs.uom_value_ids.filtered(lambda x: x.uom_id.name == "PCSPS").uom_value
            # sheet = docs.uom_value_ids.filtered(lambda x: x.uom_id.name == "SHEET").uom_value
            # 判断是否不为0
            if pnl_width and pnl_length and set_width and set_length and pcs_width and pcs_length and panel and pcs and set and pcs_in_sheet:
                pass
            else:
                raise UserError(_('Please input all unit of measure values'))
            # sheet_size_string = str(sheet_width) + ' * ' + str(sheet_length)
            # sheet_are = float(sheet_width) * float(sheet_length) / 1000000
            pnl_are = float(pnl_width) * float(pnl_length) / 1000000
            pnl_size_string = f"{format_number(pnl_length)} * {format_number(pnl_width)}"
            set_size_string = f"{format_number(set_width)} * {format_number(set_length)}"
            pcs_size_string = f"{format_number(pcs_width)} * {format_number(pcs_length)}"
            set_in_pnl = int(panel / set)
            pcs_in_pnl = int(panel / pcs)
            pcs_in_set = int(set / pcs)
            # pnl_in_sheet = math.floor((float(sheet_width) * float(sheet_length)) / (float(pnl_width) * float(pnl_length)))
            # set_in_sheet = pnl_in_sheet * set_in_pnl
            set_in_sheet = int(pcs_in_sheet / set)

            uom_details = {
                'pln_size': pnl_size_string,
                'set_size': set_size_string,
                'pcs_size': pcs_size_string,
                # 'sheet_size': sheet_size_string,
                'set_in_pnl': set_in_pnl,
                'pcs_in_pnl': pcs_in_pnl,
                'pcs_in_set': pcs_in_set,
                'set_in_sheet': set_in_sheet,
                # 'sheet_are': sheet_are,
                'pnl_are': pnl_are,
            }
        else:
            raise UserError(_('Fields are missing or do not match. Please Check whether \n [PNLL PNLW PCS SET PANEL SetL SetW PCSL PCSW] exist'))

        return uom_details
